package com.varunest.sparkbutton.helper;

import com.varunest.sparkbutton.custom.TransceiverUtil;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;

import java.math.BigDecimal;

/**
 * DotsComponent
 *
 * @author Miroslaw Stanek on 21.12.2015.
 * @modifier Varun
 */
public class DotsComponent extends Component implements Component.DrawTask, Component.EstimateSizeListener {
    private static final int DOTS_COUNT = 10;
    private static final int OUTER_DOTS_POSITION_ANGLE = 360 / DOTS_COUNT;

    private int color1 = 0xFFFFC107;
    private int color2 = 0xFFFF9800;
    private int color3 = 0xFFFF5722;
    private int color4 = 0xFFF44336;
    private int width;
    private int height;
    private int centerX;
    private int centerY;

    private float maxOuterDotsRadius;
    private float maxInnerDotsRadius;

    private Paint[] circlePaints = new Paint[4];

    private float maxDotSize;

    private float currentProgress = 0;

    private float currentRadius1 = 0;
    private float currentDotSize1 = 0;

    private float currentDotSize2 = 0;
    private float currentRadius2 = 0;

    /**
     * DotsComponent
     *
     * @param context context
     */
    public DotsComponent(Context context) {
        super(context);
        addDrawTask(this);
        setEstimateSizeListener(this);
        init();
    }

    /**
     * DotsComponent
     *
     * @param context context
     * @param attrs attrs
     */
    public DotsComponent(Context context, AttrSet attrs) {
        super(context, attrs);
        addDrawTask(this);
        setEstimateSizeListener(this);
        init();
    }

    /**
     * DotsComponent
     *
     * @param context context
     * @param attrs attrs
     * @param defStyleAttr defStyleAttr
     */
    public DotsComponent(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        addDrawTask(this);
        setEstimateSizeListener(this);
        init();
    }

    private void init() {
        maxDotSize = Utils.dpToPx(getContext(), 4);
        for (int index = 0; index < circlePaints.length; index++) {
            circlePaints[index] = new Paint();
            circlePaints[index].setStyle(Paint.Style.FILL_STYLE);
        }
    }

    /**
     * setMaxDotSize
     *
     * @param pxUnits pxUnits
     */
    public void setMaxDotSize(int pxUnits) {
        maxDotSize = pxUnits;
    }

    private void drawOuterDotsFrame(Canvas canvas) {
        for (int index = 0; index < DOTS_COUNT; index++) {
            int cx = (int) (centerX + currentRadius1 * Math.cos(index * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
            int cy = (int) (centerY + currentRadius1 * Math.sin(index * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
            canvas.drawCircle(cx, cy, currentDotSize1, circlePaints[index % circlePaints.length]);
        }
    }

    private void drawInnerDotsFrame(Canvas canvas) {
        for (int index = 0; index < DOTS_COUNT; index++) {
            int cx = (int) (centerX + currentRadius2 * Math.cos((
                    index * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
            int cy = (int) (centerY + currentRadius2 * Math.sin((
                    index * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
            canvas.drawCircle(cx, cy, currentDotSize2,
                    circlePaints[(index + 1) % circlePaints.length]);
        }
    }

    /**
     * setCurrentProgress
     *
     * @param currentProgress currentProgress
     */
    public void setCurrentProgress(float currentProgress) {
        this.currentProgress = currentProgress;
        updateInnerDotsPosition();
        updateOuterDotsPosition();
        updateDotsPaints();
        invalidate();
    }

    private void updateInnerDotsPosition() {
        if (currentProgress < 0.3f) {
            this.currentRadius2 = (float) Utils.mapValueFromRangeToRange(
                    currentProgress, 0, 0.3f, 0.f, maxInnerDotsRadius);
        } else {
            this.currentRadius2 = maxInnerDotsRadius;
        }

        if (currentProgress < 0.2) {
            this.currentDotSize2 = maxDotSize;
        } else if (currentProgress < 0.5) {
            this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(
                    currentProgress, 0.2f, 0.5f, maxDotSize, BigDecimal.valueOf(0.3).floatValue() * maxDotSize);
        } else {
            this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(
                    currentProgress, 0.5f, 1f, maxDotSize * BigDecimal.valueOf(0.3).floatValue(), 0);
        }
    }

    private void updateOuterDotsPosition() {
        if (currentProgress < 0.3f) {
            this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(
                    currentProgress, 0.0f, 0.3f, 0, maxOuterDotsRadius * BigDecimal.valueOf(0.8).floatValue());
        } else {
            this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(
                    currentProgress, 0.3f, 1f, BigDecimal.valueOf(1).floatValue() * maxOuterDotsRadius, maxOuterDotsRadius);
        }

        if (currentProgress < 0.7) {
            this.currentDotSize1 = maxDotSize;
        } else {
            this.currentDotSize1 = (float) Utils.mapValueFromRangeToRange(
                    currentProgress, 0.7f, 1f, maxDotSize, 0);
        }
    }

    private void updateDotsPaints() {
        if (currentProgress < 0.5f) {
            float progress = (float) Utils.mapValueFromRangeToRange(
                    currentProgress, 0f, 0.5f, 0, 1f);
            circlePaints[0].setColor(new Color(new TransceiverUtil(color1, color2).getColor(progress)));
            circlePaints[1].setColor(new Color(new TransceiverUtil(color2, color3).getColor(progress)));
            circlePaints[2].setColor(new Color(new TransceiverUtil(color3, color4).getColor(progress)));
            circlePaints[3].setColor(new Color(new TransceiverUtil(color4, color1).getColor(progress)));
        } else {
            float progress = (float) Utils.mapValueFromRangeToRange(
                    currentProgress, 0.5f, 1f, 0, 1f);
            circlePaints[0].setColor(new Color(new TransceiverUtil(color2, color3).getColor(progress)));
            circlePaints[1].setColor(new Color(new TransceiverUtil(color3, color4).getColor(progress)));
            circlePaints[2].setColor(new Color(new TransceiverUtil(color4, color1).getColor(progress)));
            circlePaints[3].setColor(new Color(new TransceiverUtil(color1, color2).getColor(progress)));
        }
    }

    /**
     * setColors
     *
     * @param startColor startColor
     * @param endColor endColor
     */
    public void setColors(int startColor, int endColor) {
        color2 = color4 = startColor;
        color1 = color3 = endColor;
    }

    /**
     * onDraw
     *
     * @param component component
     * @param canvas canvas
     */
    @Override
    public void onDraw(Component component, Canvas canvas) {
        drawOuterDotsFrame(canvas);
        drawInnerDotsFrame(canvas);
    }

    /**
     * onEstimateSize
     *
     * @param widthEstimateConfig widthEstimateConfig
     * @param heightEstimateConfig heightEstimateConfig
     * @return boolean
     */
    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        width = EstimateSpec.getSize(widthEstimateConfig);
        height = EstimateSpec.getSize(heightEstimateConfig);
        setEstimatedSize(
                EstimateSpec.getChildSizeWithMode(width, width, EstimateSpec.NOT_EXCEED),
                EstimateSpec.getChildSizeWithMode(height, height, EstimateSpec.NOT_EXCEED));
        centerX = width / 2;
        centerY = height / 2;
        maxOuterDotsRadius = (float) (width / 2d - maxDotSize * 2d);
        maxInnerDotsRadius = 0.8f * maxOuterDotsRadius;
        return true;
    }
}